/*
 * @Author       : Holy Han
 * @Date         : 2023-12-06 13:41:30
 * @LastEditTime : 2023-12-18 14:56:43
 * @LastEditors  : Holy Han
 * @FilePath     : \saolei\gui\main_gui.go
 * @Description  :
 */
package gui

import (
	"log"
	"math/rand"
	"time"

	"fyne.io/fyne/v2"
	"fyne.io/fyne/v2/container"
	"fyne.io/fyne/v2/data/binding"
	"fyne.io/fyne/v2/widget"
	"holy.com/saolei/img"
)

var (
	Win fyne.Window

	Lei      = 10
	LeiBind  = binding.BindInt(&Lei)
	LeiInput *widget.Entry

	LeiFlag     = 10
	LeiFlagBind = binding.BindInt(&LeiFlag)
	LeiFlagTxt  *widget.Label

	start = false
)

func InitGui() {
	Win = fyne.CurrentApp().NewWindow("扫雷")
	Win.SetIcon(img.ImgLogoPng)
	// Win.Resize(constant.WIN_SIZE)
	Win.CenterOnScreen()
	Win.SetContent(mainWin())
	Win.SetOnClosed(mainWinClosed)
	Win.Show()
}
func mainWinClosed() {
	log.Println("Win closed")
}
func mainWin() fyne.CanvasObject {
	itemsObjects = ItemsObjects{}

	leiInputTil := widget.NewLabel("💣:")
	LeiInput = widget.NewEntryWithData(binding.IntToString(LeiBind))
	leiInputLay := container.NewHBox(leiInputTil, LeiInput)

	leiFlagTil := widget.NewLabel("🚩:")
	LeiFlagTxt = widget.NewLabelWithData(binding.IntToString(LeiFlagBind))
	leiFlagLay := container.NewHBox(leiFlagTil, LeiFlagTxt)

	top := container.NewBorder(nil, nil, leiInputLay, leiFlagLay, widget.NewLabel(""))
	btn := widget.NewButton("Start", func() {
		LeiFlagBind.Set(Lei)
		itemsObjects.Generate(Lei)
		start = true
	})
	return container.NewBorder(top, btn, nil, nil, itemsObjects.Draw(10, 10))
}

type ItemPos struct {
	X, Y int // X 横坐标, Y 纵坐标
}

type Img struct {
	widget.Icon
	tapped          func()
	tappedSecondary func()
}

func NewImg(res fyne.Resource, tapped func(), tappedSecond func()) *Img {
	img := &Img{}
	img.ExtendBaseWidget(img)
	img.SetResource(res)
	img.Resize(fyne.NewSize(64, 64))
	img.tapped = tapped
	img.tappedSecondary = tappedSecond
	return img
}
func (img *Img) Tapped(_ *fyne.PointEvent) {
	if img.tapped != nil {
		img.tapped()
	}
}

func (img *Img) TappedSecondary(_ *fyne.PointEvent) {
	if img.tappedSecondary != nil {
		img.tappedSecondary()
	}
}

type Item struct {
	Pos   ItemPos //
	Num   int     // 0:无, 1-n:周围雷数, -1:雷
	Flag  bool
	Img   *Img //
	Force *Img
	Show  bool //
}

func (im *Item) BtnTapped() {
	if start {
		im.Force.Hide()
		if im.Num == 0 {
			itemsObjects.ShowNone(im.Pos.X, im.Pos.Y)
		} else if im.Num == -1 {
			itemsObjects.Gameover()
		}
	}
}
func (im *Item) BtnTappedSecond() {
	if start {
		if LeiFlag > 0 {
			if im.Flag {
				im.Force.SetResource(img.ImgButtonPng)
				im.Flag = false
				LeiFlag++
				LeiFlagBind.Reload()
			} else {
				im.Force.SetResource(img.ImgFlagPng)
				im.Flag = true
				LeiFlag--
				LeiFlagBind.Reload()
			}
		}
		if LeiFlag == 0 {
			itemsObjects.GameEnd()
		}
	}
}

type ItemsObjects struct {
	Row   int
	Col   int
	Items [][]*Item
}

var (
	itemsObjects ItemsObjects
	numPng       = []*fyne.StaticResource{img.Img0Png, img.Img1Png, img.Img2Png, img.Img3Png, img.Img4Png, img.Img5Png, img.Img6Png, img.Img7Png, img.Img8Png}
)

func (io *ItemsObjects) Draw(row, col int) fyne.CanvasObject {
	io.Row = row
	io.Col = col
	io.Items = make([][]*Item, col)
	rowLay := container.NewHBox()
	for i := 0; i < col; i++ {
		tmp := make([]*Item, row)
		colLay := container.NewVBox()
		for j := 0; j < row; j++ {
			item := Item{Pos: ItemPos{X: i, Y: j}, Num: 0}
			item.Img = NewImg(img.Img0Png, nil, nil)
			item.Force = NewImg(img.ImgButtonPng, item.BtnTapped, item.BtnTappedSecond)
			item.Force.Hide()
			lay := container.NewStack(item.Img, item.Force)
			tmp[j] = &item
			colLay.Add(lay)
		}
		io.Items[i] = tmp
		rowLay.Add(colLay)
	}
	return rowLay
}
func (io *ItemsObjects) Generate(num int) {
	mrand := rand.New(rand.NewSource(time.Now().UnixNano()))
	pos := make([]ItemPos, num)
	for i := 0; i < num; {
		x := mrand.Intn(io.Col)
		y := mrand.Intn(io.Row)
		flag := false
		for _, v := range pos {
			if v.X == x && v.Y == y {
				flag = true
				break
			}
		}
		if flag {
			continue
		} else {
			pos[i] = ItemPos{X: x, Y: y}
			i++
		}
	}
	log.Println(pos)
	io.Reset()
	for _, v := range pos {
		io.Items[v.X][v.Y].Num = -1
	}
	io.Flags()
}
func (io *ItemsObjects) Reset() {
	for i := 0; i < io.Col; i++ {
		for j := 0; j < io.Row; j++ {
			io.Items[i][j].Num = 0
			io.Items[i][j].Force.SetResource(img.ImgButtonPng)
			io.Items[i][j].Force.Show()
			io.Items[i][j].Show = false
		}
	}
}
func (io *ItemsObjects) Flags() {
	for i := 0; i < io.Col; i++ {
		for j := 0; j < io.Row; j++ {
			if io.Items[i][j].Num == -1 {
				io.Items[i][j].Img.SetResource(img.ImgCollisionPng)
				continue
			}
			if (i-1 >= 0) && (j-1 >= 0) && (io.Items[i-1][j-1].Num == -1) {
				io.Items[i][j].Num++
			}
			if (i-1 >= 0) && (io.Items[i-1][j].Num == -1) {
				io.Items[i][j].Num++
			}
			if (i-1 >= 0) && (j+1 < io.Row) && (io.Items[i-1][j+1].Num == -1) {
				io.Items[i][j].Num++
			}
			if (j-1 >= 0) && (io.Items[i][j-1].Num == -1) {
				io.Items[i][j].Num++
			}
			if (j+1 < io.Row) && (io.Items[i][j+1].Num == -1) {
				io.Items[i][j].Num++
			}
			if (i+1 < io.Col) && (j-1 >= 0) && (io.Items[i+1][j-1].Num == -1) {
				io.Items[i][j].Num++
			}
			if (i+1 < io.Col) && (io.Items[i+1][j].Num == -1) {
				io.Items[i][j].Num++
			}
			if (i+1 < io.Col) && (j+1 < io.Row) && (io.Items[i+1][j+1].Num == -1) {
				io.Items[i][j].Num++
			}

			io.Items[i][j].Img.SetResource(numPng[io.Items[i][j].Num])
		}
	}
}

func (io *ItemsObjects) ShowNone(x, y int) {
	if io.Items[x][y].Num > 0 {
		return
	}
	if !io.Items[x][y].Show {
		io.Items[x][y].Show = true
		io.Items[x][y].Force.Hide()
	}

	if (x-1 >= 0) && (y-1 >= 0) && (io.Items[x-1][y-1].Num >= 0) && !io.Items[x-1][y-1].Show {
		io.Items[x-1][y-1].Show = true
		io.Items[x-1][y-1].Force.Hide()
		io.ShowNone(x-1, y-1)
	}
	if (x-1 >= 0) && (io.Items[x-1][y].Num >= 0) && !io.Items[x-1][y].Show {
		io.Items[x-1][y].Show = true
		io.Items[x-1][y].Force.Hide()
		io.ShowNone(x-1, y)
	}
	if (x-1 >= 0) && (y+1 < io.Row) && (io.Items[x-1][y+1].Num >= 0) && !io.Items[x-1][y+1].Show {
		io.Items[x-1][y+1].Show = true
		io.Items[x-1][y+1].Force.Hide()
		io.ShowNone(x-1, y+1)
	}
	if (y-1 >= 0) && (io.Items[x][y-1].Num >= 0) && !io.Items[x][y-1].Show {
		io.Items[x][y-1].Show = true
		io.Items[x][y-1].Force.Hide()
		io.ShowNone(x, y-1)
	}
	if (y+1 < io.Row) && (io.Items[x][y+1].Num >= 0) && !io.Items[x][y+1].Show {
		io.Items[x][y+1].Show = true
		io.Items[x][y+1].Force.Hide()
		io.ShowNone(x, y+1)
	}
	if (x+1 < io.Col) && (y-1 >= 0) && (io.Items[x+1][y-1].Num >= 0) && !io.Items[x+1][y-1].Show {
		io.Items[x+1][y-1].Show = true
		io.Items[x+1][y-1].Force.Hide()
		io.ShowNone(x+1, y-1)
	}
	if (x+1 < io.Col) && (io.Items[x+1][y].Num >= 0) && !io.Items[x+1][y].Show {
		io.Items[x+1][y].Show = true
		io.Items[x+1][y].Force.Hide()
		io.ShowNone(x+1, y)
	}
	if (x+1 < io.Col) && (y+1 < io.Row) && (io.Items[x+1][y+1].Num >= 0) && !io.Items[x+1][y+1].Show {
		io.Items[x+1][y+1].Show = true
		io.Items[x+1][y+1].Force.Hide()
		io.ShowNone(x+1, y+1)
	}
}
func (io *ItemsObjects) Gameover() {
	for i, rows := range io.Items {
		for j, item := range rows {
			if item.Num == -1 {
				io.Items[i][j].Img.SetResource(img.ImgCollisionPng)
				io.Items[i][j].Force.Hide()
			}
		}
	}
	start = false
}
func (io *ItemsObjects) GameEnd() {
	flag := Lei
	for _, rows := range io.Items {
		for _, item := range rows {
			if item.Num == -1 && item.Flag {
				flag--
			}
		}
	}
	if flag == 0 {
		for i, rows := range io.Items {
			for j, item := range rows {
				if item.Num == -1 {
					io.Items[i][j].Img.SetResource(img.ImgLogoPng)
					io.Items[i][j].Force.Hide()
				}
			}
		}
		start = false
	}
}
